﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MobySharp;
using MobySharp.Actions;
using MobySharp.Results;
using MobySharp.Results.Shared;

namespace TestProject1
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UnitTest1
    {

        //TODO: Add your key and account details here
        private const string key = "";
        private const string username = "";
        private const string password = "";

        // We overwrite this if we test all methods
        private long postID = 6250966;
        private string tinyCode = "65r1du";

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #region Additional test attributes

        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //

        #endregion

        [TestMethod]
        public void TestPostMedia()
        {
            //Tested OK
            var action = new PostMedia(username, password, GenerateSmallImage(DateTime.Now.ToString()));

            action.Title = "PostMedia at " + DateTime.Now.ToString("HH:mm:ss");
            action.Img = GenerateSmallImage(DateTime.Now.ToString());
            action.Description =
                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent nec lorem et metus iaculis molestie vel non leo. Phasellus volutpat sapien vitae nibh convallis sagittis adipiscing massa porta.";
            action.Location.Latitude = "52.23558";
            action.Location.Longitude = "5.171127";
            action.Tags.Add("unittest");
            action.Tags.Add("mobysharp");
            action.Hashtag.Add("#unittest");
            action.Hashtag.Add("#MobySharp");
            //action.TakenOn = DateTime.Now.AddDays(-3).ToString("s");


            var moby = new Mobypicture(key);

            BasicResult response = moby.PostMedia(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Url!=null && response.Url.Contains("moby.to"), "Post media returned a url that did not contain 'moby.to'");
        }

        [TestMethod]
        public void TestPostMedia_OGG()
        {
            //Tested OK
            Assembly assembly = Assembly.GetExecutingAssembly();

            var path = Environment.CurrentDirectory + "\\whale.ogg";
            var stream = assembly.GetManifestResourceStream("TestProject1.whale.ogg");
            
            using (Stream output = new FileStream (path, FileMode.CreateNew))
            {
                byte[] buffer = new byte[32*1024];
                int read;

                while ( (read=stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    output.Write(buffer, 0, read);
                }
            }

            var action = new PostMedia(username, password, path);

            action.Title = "PostMedia (OGG) at " + DateTime.Now.ToString("HH:mm:ss");
            action.Description = "Whale sound - http://en.wikipedia.org/wiki/File:Killer_whale.ogg";
            action.Location.Latitude = "19.072501";
            action.Location.Longitude = "-110.088501";
            action.Tags.Add("unittest");
            action.Tags.Add("ogg");
            action.Tags.Add("mobysharp");
            action.Hashtag.Add("#unittest");
            action.Hashtag.Add("#MobySharp");

            var moby = new Mobypicture(key);

            BasicResult response = moby.PostMedia(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Url != null && response.Url.Contains("moby.to"), "Post media returned a url that did not contain 'moby.to'");
        }

        [TestMethod]
        public void TestGetThumb()
        {
            //Tested OK
            var action = new GetThumb("http://moby.to/" + tinyCode, ThumbSize.medium);

            var moby = new Mobypicture(key);
            BasicResult response = moby.GetThumb(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Url != null && response.Url.Contains("mobypicture.com"), "Given url " + action.TinyURL + " is not correct");
        }


        [TestMethod]
        public void TestGetMediaInfo()
        {
            //Tested OK
            var action = new GetMediaInfo(tinyCode);

            var moby = new Mobypicture(key);
            MediaInfoResult response = moby.GetMediaInfo(action);

            PrintMediaInfo(response.Post);

            postID = response.Post.ID;

            Assert.IsTrue(response.Post.LinkTiny.Contains(tinyCode),
                          "Given tiny code " + action.TinyURLCode + " did not return the right object");
        }


        [TestMethod]
        public void TestCheckCredentialsOK()
        {
            //Tested OK

            var action = new CheckCredentials(username, password);
            var moby = new Mobypicture(key);
            BasicResult response = moby.CheckCredentials(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Result.Code == 0,
                          "Credentials supposed to be OK (0) but return value was " + response.Result.Code);
        }

        [TestMethod]
        public void TestCheckCredentialsNOK()
        {
            //Tested OK

            var action = new CheckCredentials(username, password + "XYZ");
            var moby = new Mobypicture(key);
            BasicResult response = moby.CheckCredentials(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Result.Code == 401,
                          "Credentials supposed to be NOK (401) but return value was " + response.Result.Code);
        }


        [TestMethod]
        public void TestPostComment()
        {
            //Tested OK

            var action = new PostComment(tinyCode, "This comment is made using a unit test\r\nw00t! :D");
            action.Username = username;
            action.Password = password;
            action.Tweet = 0;

            var moby = new Mobypicture(key);
            BasicResult response = moby.PostComment(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Result.Code == 0, "Posting a comment failed, returned Code " + response.Result.Code);
        }

        [TestMethod]
        public void TestGetCommentsByTinyURL()
        {
            //Tested OK

            var action = new GetComments(tinyCode);

            var moby = new Mobypicture(key);
            CommentsResult response = moby.GetComments(action);

            PrintCommentResult(response);

            Assert.IsTrue(response.Result.Code == 0,
                          "Getting comments by TinyCode failed, returned Code " + response.Result.Code);
        }

        [TestMethod]
        public void TestGetCommentsByPostId()
        {
            var action = new GetComments(postID);

            var moby = new Mobypicture(key);
            CommentsResult response = moby.GetComments(action);

            PrintCommentResult(response);

            Assert.IsTrue(response.Result.Code == 0,
                          "Getting comments by Post ID failed, returned Code " + response.Result.Code);
        }

        [TestMethod]
        public void TestSearchPosts()
        {
            var action = new SearchPosts();
            action.ItemsPerPage = 5;
            action.Page = 2;
            action.Terms = "whale";

            //action.GeoCountry = "NL";

            var moby = new Mobypicture(key);
            SearchResult response = moby.SearchPosts(action);
            int c = 0;
            foreach (SearchResult.SesarchResult result in response.Results)
            {
                c++;
                PrintMobyUser(result.User);
                PrintMediaInfo(result.Post);
                if (c > 3) break;
            }

            Assert.IsTrue(response.TotalResults > 10,
                          "Search for '" + action.Terms + "' returned less than 10 results, this is unlikely");
        }

        [TestMethod]
        public void TestCreateUser()
        {
            // NOTE: Need unique emailaddress! Else it will fail.

            var r = new Random();
            string nr = r.Next(1, 50000).ToString();
            var action = new CreateUser("TestUser" + nr, "1234", "test" + nr + "@example.com", "Test", "User", YesNo.no,
                                        YesNo.yes);

            var moby = new Mobypicture(key);


            BasicResult response = moby.CreateUser(action);

            PrintBasicResult(response);

            Assert.IsTrue(response.Result.Code == 0,
                          "CreateUser did not succeed. Return code expected: 0 but got " + response.Result.Code);
        }

        [TestMethod]
        public void TestGetUser()
        {
            //Tested OK

            var action = new GetUser(username);

            var moby = new Mobypicture(key);
            UserResult response = moby.GetUser(action);

            Console.WriteLine("Firstname: {0}", response.Firstname);
            Console.WriteLine("Lastname: {0}", response.Lastname);
            Console.WriteLine("Post count: {0}", response.PostCount);
            Console.WriteLine("Friends count: {0}", response.FriendsCount);
            Console.WriteLine("Followers count: {0}", response.FollowersCount);
            Console.WriteLine("URL: {0}", response.URL);
            Console.WriteLine("Avatar: {0}", response.AvatarURL);

            Assert.IsTrue(response.Result.Code.Equals(0) && response.Username.Equals(username),
                          "GetUser did not return the right user info");
        }


        [TestMethod]
        public void TestValidateRequiredProperty()
        {
            //Tested OK

            // Should break on empty property!
            var action = new GetUser(string.Empty);

            try
            {
                var moby = new Mobypicture(key);
                moby.GetUser(action);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex.Message.Contains("is required"),
                              "A missing required property did not throw an exception!");
            }
        }


        [TestMethod]
        public void TestValidateMaxLengthProperty()
        {
            //Tested OK

            // Should break on length!
            var action = new GetMediaInfo("VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongTinyURLCode");

            try
            {
                var moby = new Mobypicture(key);
                moby.GetMediaInfo(action);
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex.Message.Contains("has a max length of"),
                              "A missing required property did not throw an exception!");
            }
        }

        [TestMethod]
        public void TestGetFriends()
        {
            var action = new GetFriends(username);

            var moby = new Mobypicture(key);
            FriendsResult response = moby.GetFriends(action);

            Assert.IsTrue(response.Result.Code == 0, "Getting friends failed, returned Code " + response.Result.Code);
        }

        [TestMethod]
        public void TestAddLike()
        {
            var action = new AddLike(this.tinyCode);

            var moby = new Mobypicture(key);
            LikeResult response = moby.AddLike(action);

            Assert.IsTrue(response.Result.Code == 0, "Adding the Like failed, returned Code " + response.Result.Code);
            Assert.IsTrue(response.Votes > 1, "Adding the like returned les than 1 vote");
        }


        [TestMethod]
        public void TestGetLikes()
        {
            var action = new GetLikes(this.tinyCode);

            var moby = new Mobypicture(key);
            LikeResult response = moby.GetLikes(action);

            Assert.IsTrue(response.Result.Code == 0, "Getting Likes failed, returned Code " + response.Result.Code);
            Assert.IsTrue(response.Votes > 1, "Adding the like returned les than 1 vote");
        }



        private void PrintBasicResult(BasicResult response)
        {
            Console.WriteLine("Response code: {0}", response.Result.Code);
            Console.WriteLine("Response message: {0}", response.Result.Message);
            Console.WriteLine("URL: {0}", response.Url);
        }

        private void PrintCommentResult(CommentsResult response)
        {
            Console.WriteLine("Comments: {0}", response.Comments.Count);
            foreach (CommentsResult.Comment comment in response.Comments)
            {
                Console.WriteLine("[COMMENT]");
                Console.WriteLine("Name: {0}", comment.Name);
                Console.WriteLine("Username: {0}", comment.Username);
                Console.WriteLine("Avatar URL : {0}", comment.AvatarURL);
                Console.WriteLine("Avatar URL Small: {0}", comment.AvatarURLSmall);
                Console.WriteLine("Created: {0}", comment.CreatedOn);
            }
        }

        private void PrintMediaInfo(MobyPost post)
        {
            Console.WriteLine("Comments: {0}", post.Comments);
            Console.WriteLine("Created on: {0}", post.CreatedOn);
            Console.WriteLine("Created on Epoch: {0}", post.CreatedOnEpoch);
            Console.WriteLine("Description: {0}", post.Description);
            Console.WriteLine("Title: {0}", post.Title);
            Console.WriteLine("Views: {0}", post.Views);
            Console.WriteLine("ID: {0}", post.ID);
            Console.WriteLine("Lat/long: {0}", post.LatLong);
            Console.WriteLine("Link: {0}", post.Link);
            Console.WriteLine("Tiny link: {0}", post.LinkTiny);

            Console.WriteLine("\r\n[DEVICE]");
            Console.WriteLine("Manufacturer: {0}", post.Device.Manufacturer);
            Console.WriteLine("Model: {0}", post.Device.Model);

            Console.WriteLine("\r\n[MEDIA]");
            Console.WriteLine("Type: {0}", post.Media.Type);
            Console.WriteLine("Full URL: {0}", post.Media.Full);
            Console.WriteLine("Square URL: {0}", post.Media.Square);
            Console.WriteLine("Thumb URL: {0}", post.Media.Thumb);
            Console.WriteLine("Original height: {0}", post.Media.OriginalHeight);
            Console.WriteLine("Original width: {0}", post.Media.OriginalWidth);
        }

        private void PrintMobyUser(MobyUser user)
        {
            Console.WriteLine("Avatar: {0}", user.Avatar);
            Console.WriteLine("AvatarSmall: {0}", user.AvatarSmall);
            Console.WriteLine("Firstname: {0}", user.Firstname);
            Console.WriteLine("Lastname: {0}", user.Lastname);
            Console.WriteLine("Username: {0}", user.Username);
        }

        private string GenerateSmallImage(string text)
        {
            string filepath = "C:\\MobySharpTestImage.jpg";
            Brush whiteBrush = new SolidBrush(Color.FloralWhite);
            Brush redBrush = new SolidBrush(Color.OrangeRed);
            var font = new Font("Arial", 20F);


            using (var bmp = new Bitmap(640, 480))
            {
                bmp.SetResolution(67.996f, 67.996f);
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    SizeF stringSize = g.MeasureString(text, font);

                    Assembly assembly = Assembly.GetExecutingAssembly();
                    g.DrawImage(new Bitmap(assembly.GetManifestResourceStream("TestProject1.testbeeld.png")), 0, 0);

                    g.DrawString(text, font, whiteBrush,
                                 new PointF(bmp.Width - (stringSize.Width + 2), bmp.Height - (stringSize.Height + 2)));
                    g.DrawString(text, font, redBrush,
                                 new PointF(bmp.Width - (stringSize.Width + 3), bmp.Height - (stringSize.Height + 3)));

                    g.CompositingQuality = CompositingQuality.HighQuality;
                    g.SmoothingMode = SmoothingMode.HighQuality;

                    g.Save();

                    bmp.Save(filepath, ImageFormat.Jpeg);
                }
            }

            return filepath;
        }
    }
}